package com.zhw.client;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import io.netty.channel.EventLoop;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/** https://blog.csdn.net/u012129558/article/details/82898518
 * @author weizhang52
 * @description: 读取服务器返回的响应信息
 * 每一个Channel都拥有自己的ChannelPipeline，它是ChannelHandler的容器，负责ChannelHandler的管理、事件拦截、消息调度.每一个ChannelPipeline中可以包含多个ChannelHandler
 * ChannelHandler的主要功能是为I/O操作进行拦截和处理，我们可以称呼它为：I/O事件拦截器
 * 自定义的ChannelHandler只需要继承ChannelHandlerAdapter并覆盖需要用到的方法
 * @date 2019/4/16
 * @modify
 */
@Slf4j
@ChannelHandler.Sharable
public class HelloNettyClientHandler extends ChannelInboundHandlerAdapter {

    // Inbound表示read,用来接收消息

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        try {
            ByteBuf bb = (ByteBuf)msg;
            byte[] respByte = new byte[bb.readableBytes()];
            bb.readBytes(respByte);
//            String respStr = new String(respByte, Constant.charset);
            handlerObject(ctx, msg);
            log.info("[HelloNettyClientHandler] client收到响应 = {}", msg);

            // 直接转成对象
//          handlerObject(ctx, msg);

        } finally{
            // 必须释放msg数据
            ReferenceCountUtil.release(msg);
            log.info("[HelloNettyClientHandler] 释放msg数据");
        }

    }

    private void handlerObject(ChannelHandlerContext ctx, Object msg) {

//        Student student = (Student)msg;
//        log.info("server 获取信息："+student.getId()+student.getName());
        log.info("[HelloNettyClientHandler] server 获取信息："+ msg);
    }


    // 数据读取完毕的处理
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.info("[HelloNettyClientHandler] 客户端读取数据完毕");
    }

    // 出现异常的处理
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("[HelloNettyClientHandler] client 读取数据出现异常");
        ctx.close();
    }

    /**
     * ChannelHandler与ChannelHandlerContext是一一对应的关系，ChannelPipeline并不是直接管理ChannelHandler，而是通过ChannelHandlerContext来间接管理
     * @param ctx 返回该ChannelHandlerContext所绑定的Channel
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.warn("[channelInactive] 通道断开,自动重连");
        // 2019-06-11新增逻辑：使用过程中断线重连--ctx.channel()返回该ChannelHandlerContext所绑定的Channel
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(() -> {
            try {
                log.info("[channelInactive] 开始netty重新连接服务端");
                HelloNettyClient.start();
                log.info("[channelInactive] 已执行netty重新连接服务端");
            } catch (Exception e) {
                log.error("[channelInactive] 执行netty重新连接服务端出错e={}",e.getMessage());
                e.printStackTrace();
            }

        },1L,TimeUnit.SECONDS);

        super.channelInactive(ctx);
//        ctx.fireChannelInactive();

    }

}
